﻿using System;
using System.Collections.Generic;

using SBPweb.Forge.Contracts.Events;

using SBPweb.Communication.Shared.Library.Contacts;
using SBPweb.Communication.Shared.Library.Connections;

using SBPweb.Communication.Client.Library.Xmpp.Contacts;

namespace SBPweb.Communication.Client.Library.Xmpp.Connections
{

    partial class ConnectionManager : ConnectionManagerBase
    {

        #region Internal fields

        internal protected agsXMPP.XmppClientConnection client;

        internal agsXMPP.Jid localJid;

        #endregion

        #region Constructor logic

        #endregion

        #region Property accessors

        public override string UserName
        {
            get
            {
                return localJid.User;
            }
            protected set
            {
                localJid.User = value;
            }
        }

        public override string Resource
        {
            get
            {
                return client.Resource;
            }
            set
            {
                client.Resource = value;
            }
        }

        #endregion

        #region Methods

        #region Connectivity

        public override void Connect(string userName, string password)
        {
            localJid = new agsXMPP.Jid(userName, client.Server, client.Resource);
            OnConnecting(this, EventArgs.Empty);
            client.Open(userName, password);
        }

        public override void Disconnect()
        {
            CancelEventArgs cea = new CancelEventArgs();
            OnDisconnecting(this, cea);
            if (!cea.Cancel)
            {
                client.Close();
            }
        }

        private void OnClientClose(object sender)
        {
            OnDisconnected(sender, EventArgs.Empty);
        }

        private void OnClientError(object sender, Exception ex)
        {
            throw ex;
        }

        #endregion

        #region State management

        protected override void OnSetPresenceState(object sender, ContactPresenceStateBaseCancelEventArgs e)
        {
            client.Show = ContactPresenceState.GetShowByAvailabilty(e.State.Availability);
            client.Status = e.State.StatusMessage;
            client.SendMyPresence();
        }

        #endregion

        #region Event handlers

        #region Life cycle

        protected override void OnInitialize()
        {
            client = new agsXMPP.XmppClientConnection();

            client.AutoPresence = Configuration.SendAvailabilityWhenConnected;
            client.AutoResolveConnectServer = true;
            client.Server = Configuration.Server;
            client.Port = Configuration.Port;
            client.Resource = Configuration.Resource;
            client.UseSSL = Configuration.IsSslNeeded;

            client.Show = ContactPresenceState.GetShowByAvailabilty(Configuration.DefaultAvailability);

            client.OnError += new agsXMPP.ErrorHandler(OnClientError);
            client.OnAuthError += new agsXMPP.XmppElementHandler(OnClientAuthError);
            client.OnLogin += new agsXMPP.ObjectHandler(OnClientLogin);
            client.OnClose += new agsXMPP.ObjectHandler(OnClientClose);
            client.OnPresence += new agsXMPP.protocol.client.PresenceHandler(OnPresence);
        }

        protected override void OnTerminate()
        {
            if (IsConnected)
            {
                Disconnect();
            }

            client.OnError += new agsXMPP.ErrorHandler(OnClientError);
            client.OnAuthError -= new agsXMPP.XmppElementHandler(OnClientAuthError);
            client.OnLogin -= new agsXMPP.ObjectHandler(OnClientLogin);
            client.OnClose -= new agsXMPP.ObjectHandler(OnClientClose);
            client.OnPresence -= new agsXMPP.protocol.client.PresenceHandler(OnPresence);
            client = null;
        }

        #endregion

        #region Client authentication

        private void OnClientAuthError(object sender, agsXMPP.Xml.Dom.Element e)
        {
            IsConnected = false;
        }

        private void OnClientLogin(object sender)
        {
            IsConnected = true;
            OnConnected(sender, EventArgs.Empty);
        }

        #endregion

        private void OnPresence(object sender, agsXMPP.protocol.client.Presence e)
        {
            if (e.From.Equals(localJid))
            {
                OnPresenceStateChanged(sender, new ContactPresenceStateBaseCancelEventArgs(new Contact(localJid), new ContactPresenceState(e)));
            }
        }

        #endregion

        #endregion

    }

}